when deleting a remote locked file, provide needed lock headers
authorMatthieu Gallien <matthieu.gallien@nextcloud.com>
Mon, 3 Mar 2025 14:24:21 +0000 (15:24 +0100)
committerbackportbot[bot] <backportbot[bot]@users.noreply.github.com>
Mon, 3 Mar 2025 16:07:07 +0000 (16:07 +0000)
Signed-off-by: Matthieu Gallien <matthieu.gallien@nextcloud.com>
src/libsync/basepropagateremotedeleteencrypted.cpp
src/libsync/deletejob.cpp
src/libsync/deletejob.h
src/libsync/propagateremotedelete.cpp
src/libsync/propagateremotedeleteencryptedrootfolder.cpp
src/libsync/propagateremotemkdir.cpp
src/libsync/propagateupload.cpp
src/libsync/propagateuploadng.cpp
src/libsync/syncengine.cpp

index 4baf8fa8cae6163305f69c0477704d96eea5cca9..05c0ad9ed2b0579bb15fa958d10dbabdb8409b89 100644 (file)
@@ -153,7 +153,7 @@ void BasePropagateRemoteDeleteEncrypted::deleteRemoteItem(const QString &filenam
 {
     qCInfo(ABSTRACT_PROPAGATE_REMOVE_ENCRYPTED) << "Deleting nested encrypted item" << filename;
 
-    const auto deleteJob = new DeleteJob(_propagator->account(), _propagator->fullRemotePath(filename), this);
+    const auto deleteJob = new DeleteJob(_propagator->account(), _propagator->fullRemotePath(filename), {}, this);
     if (_encryptedFolderMetadataHandler && _encryptedFolderMetadataHandler->folderMetadata()
         && _encryptedFolderMetadataHandler->folderMetadata()->isValid()) {
         deleteJob->setFolderToken(_encryptedFolderMetadataHandler->folderToken());
index 83666ba9f29399db6a545ab5770be7a4e7e54905..f81c83c87f2a6654186887c8a4574597cc1e6760 100644 (file)
@@ -20,13 +20,15 @@ namespace OCC {
 
 Q_LOGGING_CATEGORY(lcDeleteJob, "nextcloud.sync.networkjob.delete", QtInfoMsg)
 
-DeleteJob::DeleteJob(AccountPtr account, const QString &path, QObject *parent)
+DeleteJob::DeleteJob(AccountPtr account, const QString &path, const QMap<QByteArray, QByteArray> &headers, QObject *parent)
     : SimpleFileJob(account, path, parent)
+    , _headers(headers)
 {
 }
 
-DeleteJob::DeleteJob(AccountPtr account, const QUrl &url, QObject *parent)
+DeleteJob::DeleteJob(AccountPtr account, const QUrl &url, const QMap<QByteArray, QByteArray> &headers, QObject *parent)
     : SimpleFileJob(account, QString(), parent)
+    , _headers(headers)
     , _url(url)
 {
 }
@@ -38,6 +40,10 @@ void DeleteJob::start()
         req.setRawHeader("e2e-token", _folderToken);
     }
 
+    for (auto oneHeaderIt = _headers.begin(); oneHeaderIt != _headers.end(); ++oneHeaderIt) {
+        req.setRawHeader(oneHeaderIt.key(), oneHeaderIt.value());
+    }
+
     if (_url.isValid()) {
         startRequest("DELETE", _url, req);
     } else {
index 4bc6351e5c5e3774b930912d7cf78d6fc00e86ec..d244e5a85ab70602da78b36e6863edc1b8b10a4b 100644 (file)
@@ -27,8 +27,8 @@ class DeleteJob : public SimpleFileJob
 {
     Q_OBJECT
 public:
-    explicit DeleteJob(AccountPtr account, const QString &path, QObject *parent = nullptr);
-    explicit DeleteJob(AccountPtr account, const QUrl &url, QObject *parent = nullptr);
+    explicit DeleteJob(AccountPtr account, const QString &path, const QMap<QByteArray, QByteArray> &headers = {}, QObject *parent = nullptr);
+    explicit DeleteJob(AccountPtr account, const QUrl &url, const QMap<QByteArray, QByteArray> &headers = {}, QObject *parent = nullptr);
 
     void start() override;
 
@@ -36,6 +36,7 @@ public:
     void setFolderToken(const QByteArray &folderToken);
 
 private:
+    QMap<QByteArray, QByteArray> _headers = {};
     QUrl _url; // Only used if the constructor taking a url is taken.
     QByteArray _folderToken;
 };
index 708b0f2ed2a0a95dcbcb6cac87bd933e289bca78..b376366073be718f2ed5e2dac39d20f6e63a093d 100644 (file)
@@ -71,7 +71,11 @@ void PropagateRemoteDelete::createDeleteJob(const QString &filename)
 
     qCInfo(lcPropagateRemoteDelete) << "Deleting file, local" << _item->_file << "remote" << remoteFilename;
 
-    _job = new DeleteJob(propagator()->account(), propagator()->fullRemotePath(remoteFilename), this);
+    auto headers = QMap<QByteArray, QByteArray>{};
+    if (_item->_locked == SyncFileItem::LockStatus::LockedItem) {
+        headers[QByteArrayLiteral("If")] = (QLatin1String("<") + propagator()->account()->davUrl().toString() + _item->_file + "> (<opaquelocktoken:" + _item->_lockToken.toUtf8() + ">)").toUtf8();
+    }
+    _job = new DeleteJob(propagator()->account(), propagator()->fullRemotePath(remoteFilename), headers, this);
     connect(_job.data(), &DeleteJob::finishedSignal, this, &PropagateRemoteDelete::slotDeleteJobFinished);
     propagator()->_activeJobList.append(this);
     _job->start();
index 849e5f2b27e216e9e781dadb4b1eef0425143bd9..55dd4910fa1c5c8519a26e7953cdf713acd99861 100644 (file)
@@ -181,7 +181,7 @@ void PropagateRemoteDeleteEncryptedRootFolder::deleteNestedRemoteItem(const QStr
 {
     qCInfo(PROPAGATE_REMOVE_ENCRYPTED_ROOTFOLDER) << "Deleting nested encrypted remote item" << filename;
 
-    auto deleteJob = new DeleteJob(_propagator->account(), _propagator->fullRemotePath(filename), this);
+    auto deleteJob = new DeleteJob(_propagator->account(), _propagator->fullRemotePath(filename), {}, this);
     deleteJob->setFolderToken(folderToken());
     deleteJob->setProperty(encryptedFileNamePropertyKey, filename);
 
index 868614e68f8f4bcc5790e025fbb3be48b3030a86..f39f3918861068980fed93b498492740cc5bb776 100644 (file)
@@ -59,8 +59,9 @@ void PropagateRemoteMkdir::start()
     }
 
     _job = new DeleteJob(propagator()->account(),
-        propagator()->fullRemotePath(_item->_file),
-        this);
+                         propagator()->fullRemotePath(_item->_file),
+                         {},
+                         this);
     connect(qobject_cast<DeleteJob *>(_job), &DeleteJob::finishedSignal, this, &PropagateRemoteMkdir::slotMkdir);
     _job->start();
 }
index 92dd47b54b7bf13cb226ca7d749237f6fc65a158..a38359d9449e47b0dcbaf16475147e80f45e8622 100644 (file)
@@ -297,8 +297,9 @@ void PropagateUploadFileCommon::startUploadFile() {
 
     qDebug() << "Deleting the current";
     auto job = new DeleteJob(propagator()->account(),
-        propagator()->fullRemotePath(_fileToUpload._file),
-        this);
+                             propagator()->fullRemotePath(_fileToUpload._file),
+                             {},
+                             this);
     _jobs.append(job);
     connect(job, &DeleteJob::finishedSignal, this, &PropagateUploadFileCommon::slotComputeContentChecksum);
     connect(job, &QObject::destroyed, this, &PropagateUploadFileCommon::slotJobDestroyed);
index be5cd5995a9b381eb3c9468532f319aa020fa09b..7444d43182172fe4ff63df6715fda8c313235bb4 100644 (file)
@@ -121,7 +121,7 @@ void PropagateUploadFileNG::doStartUpload()
         // The upload info is stale. remove the stale chunks on the server
         _transferId = progressInfo._transferid;
         // Fire and forget. Any error will be ignored.
-        (new DeleteJob(propagator()->account(), chunkUploadFolderUrl(), this))->start();
+        (new DeleteJob(propagator()->account(), chunkUploadFolderUrl(), {}, this))->start();
         // startNewUpload will reset the _transferId and the UploadInfo in the db.
     }
 
@@ -168,7 +168,7 @@ void PropagateUploadFileNG::slotPropfindFinished()
 
         // Wipe the old chunking data.
         // Fire and forget. Any error will be ignored.
-        (new DeleteJob(propagator()->account(), chunkUploadFolderUrl(), this))->start();
+        (new DeleteJob(propagator()->account(), chunkUploadFolderUrl(), {}, this))->start();
 
         propagator()->_activeJobList.append(this);
         startNewUpload();
@@ -186,7 +186,7 @@ void PropagateUploadFileNG::slotPropfindFinished()
         // we should remove the later chunks. Otherwise when we do dynamic chunk sizing, we may end up
         // with corruptions if there are too many chunks, or if we abort and there are still stale chunks.
         for (const auto &serverChunk : std::as_const(_serverChunks)) {
-            auto job = new DeleteJob(propagator()->account(), Utility::concatUrlPath(chunkUploadFolderUrl(), serverChunk.originalName), this);
+            auto job = new DeleteJob(propagator()->account(), Utility::concatUrlPath(chunkUploadFolderUrl(), serverChunk.originalName), {}, this);
             QObject::connect(job, &DeleteJob::finishedSignal, this, &PropagateUploadFileNG::slotDeleteJobFinished);
             _jobs.append(job);
             job->start();
index 5501971737c413e2b6e669f3c3630a6ca98471ce..24c86a73b9a0d11f1f6bcf64bb694cde5e611780 100644 (file)
@@ -254,7 +254,7 @@ void SyncEngine::deleteStaleUploadInfos(const SyncFileItemVector &syncItems)
             if (!transferId)
                 continue; // Was not a chunked upload
             QUrl url = Utility::concatUrlPath(account()->url(), QLatin1String("remote.php/dav/uploads/") + account()->davUser() + QLatin1Char('/') + QString::number(transferId));
-            (new DeleteJob(account(), url, this))->start();
+            (new DeleteJob(account(), url, {}, this))->start();
         }
     }
 }